package legumes.shared.domain;

import java.io.Serializable;

public class LatLng implements Serializable {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private double latitude;
	private double longitude;

	public LatLng(){
		this(0, 0);
	}
	
	public LatLng(double latitude_, double longitude_) {
		super();
		setLatitude(latitude_);
		setLongitude(longitude_);
	}

	@Override
	public String toString() {
		return "[" + getLatitude() + "; " + getLongitude() + "]";
	}

	public double getLatitude() {
		return latitude;
	}

	public void setLatitude(double latitude) {
		this.latitude = latitude;
	}

	public double getLongitude() {
		return longitude;
	}

	public void setLongitude(double longitude) {
		this.longitude = longitude;
	}
	
	public boolean isInBound(LatLng northEastBound_, LatLng southWestBound_){
		return getLatitude() < northEastBound_.getLatitude() && getLatitude() > southWestBound_.getLatitude()
		&& getLongitude() < northEastBound_.getLongitude() && getLongitude() > southWestBound_.getLongitude();
	}
	
	public double getLatitudeRadians(){
		return Math.toRadians(getLatitude());
	}

	public double getLongitudeRadians(){
		return Math.toRadians(getLongitude());
	}
	
	public double computeDistance(LatLng dest_){
		return Math.acos(Math.sin(getLatitudeRadians())*
				Math.sin(dest_.getLatitudeRadians())+
				Math.cos(getLatitudeRadians())*Math.cos(dest_.getLatitudeRadians())*
				Math.cos(dest_.getLongitudeRadians()-getLongitudeRadians()) )*6371;
	}
	
	/**
	 * This LatLng point object is considered as the center of the circle.
	 * This method tests if in case where a circle has a center outside of the bounds, 
	 * if there is a part of the circle area which is inside of the rectangle bounds defined by
	 * the two points northEastBound_ and southWestBound_.
	 * 
	 * @param northEastBound_
	 * @param southWestBound_
	 * @param circleRadius_
	 * @return
	 */
	public boolean isCircleCoversBounds(LatLng northEastBound_, LatLng southWestBound_, int circleRadius_){
		// 01) Most simple algorithm which check if the center point is in a larger area
		//We define a larger area to be sure to not forget any circle covered area
		LatLng northEastBoundLarger = new LatLng(northEastBound_.getLatitude()-circleRadius_,
		 northEastBound_.getLongitude()+circleRadius_);
		LatLng southWestBoundLarger = new LatLng(southWestBound_.getLatitude()+circleRadius_,
				 southWestBound_.getLongitude()-circleRadius_);
		return isInBound(northEastBoundLarger, southWestBoundLarger);
		
// 02) Complex algorithm which checks all the border line
//		//We start from the northEastBound_, we check by going down to the south side
//		//then we check by going to the west side
//		//then we check by going to the north side
//		//and finally we come back to the north east point by going to the east
//		int circleDiameterRadius = circleRadius_*2;
//		//We define a larger area to be sure to not forget any circle covered area
//		LatLng northEastBoundLarger = new LatLng(northEastBound_.getLatitude()-circleRadius_,
//												 northEastBound_.getLongitude()+circleRadius_);
//		LatLng southWestBoundLarger = new LatLng(southWestBound_.getLatitude()+circleRadius_,
//												 southWestBound_.getLongitude()-circleRadius_);
//		boolean isInBound = false;
//		LatLng curPointToCheck = northEastBoundLarger;
//		int direction = 0;
//		while( !isInBound && curPointToCheck != null){
//			isInBound = computeDistance(curPointToCheck) <= circleRadius_;
//			if( ! isInBound ){
//				switch(direction ){
//					case 0: //Going to south
//						curPointToCheck = new LatLng(curPointToCheck.getLatitude()-circleDiameterRadius,
//								curPointToCheck.getLongitude());
//						if( curPointToCheck.getLatitude()<southWestBoundLarger.getLatitude() ){
//							curPointToCheck = new LatLng(	southWestBoundLarger.getLatitude(),
//															northEastBoundLarger.getLongitude());
//							direction++;
//						}
//						break;
//					case 1: //Going to west
//						curPointToCheck = new LatLng(curPointToCheck.getLatitude(),
//								curPointToCheck.getLongitude()-circleDiameterRadius);
//						if( curPointToCheck.getLongitude()<southWestBoundLarger.getLongitude() ){
//							curPointToCheck = new LatLng(	southWestBoundLarger.getLatitude(),
//															southWestBoundLarger.getLongitude());
//							direction++;
//						}
//						break;
//					case 2: //Going to north
//						curPointToCheck = new LatLng(curPointToCheck.getLatitude()+circleDiameterRadius,
//								curPointToCheck.getLongitude());
//						if( curPointToCheck.getLatitude()>northEastBoundLarger.getLatitude() ){
//							curPointToCheck = new LatLng(	northEastBoundLarger.getLatitude(),
//															southWestBoundLarger.getLongitude());
//							direction++;
//						}
//						break;
//					case 3: //Going back to east until north east point
//						curPointToCheck = new LatLng(curPointToCheck.getLatitude(),
//								curPointToCheck.getLongitude()+circleDiameterRadius);
//						if( curPointToCheck.getLongitude()>northEastBoundLarger.getLongitude() ){
//							curPointToCheck = null;
//							direction++;
//						}
//						break;
//					default :
//						curPointToCheck = null;
//				}
//			}
//		}
		
		
// 03) Simple algorithm which checks only the corner
//		boolean isInBound = computeDistance(northEastBound_) <= circleRadius_;
//		if(!isInBound){
//			isInBound = computeDistance(southWestBound_) <= circleRadius_;
//			if(!isInBound){
//				LatLng northWestBound = new LatLng(northEastBound_.getLatitude(), southWestBound_.getLongitude());
//				isInBound = computeDistance(northWestBound) <= circleRadius_;
//				if(!isInBound){
//					LatLng southEastBound = new LatLng(southWestBound_.getLatitude(), northEastBound_.getLongitude());
//					isInBound = computeDistance(southEastBound) <= circleRadius_;
//				}
//			}
//		}
//		return isInBound;
	}
}
